package com.central.scheduler.dao.model;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.central.common.entity.TaskContent;
import com.central.common.enums.TaskType;
import com.central.common.handler.ListLongToStringHandler;
import com.central.common.handler.ListPropToStringHandler;
import com.central.common.handler.TaskParamsToStringHandler;
import com.central.common.model.ResourceInfo;
import com.central.common.model.SuperEntity;
import com.central.common.model.TaskDefinition;
import com.central.common.properties.Property;
import com.central.scheduler.common.enums.ExecutionStatus;
import com.central.scheduler.common.enums.Flag;
import com.central.scheduler.common.enums.Priority;
import com.central.scheduler.common.task.AbstractParameters;
import com.central.scheduler.common.task.TaskTimeoutParameter;
import com.central.scheduler.common.task.dependent.DependentParameters;
import com.central.scheduler.common.task.switchtask.SwitchParameters;
import com.central.scheduler.common.utils.DateUtils;
import com.central.scheduler.dao.handler.TaskTimeoutParamsToStringHandler;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.ibatis.type.JdbcType;

import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.baomidou.mybatisplus.annotation.FieldStrategy.NOT_NULL;
import static com.central.scheduler.common.Constants.SEC_2_MINUTES_TIME_UNIT;

/**
 * @author Tindy
 * @date 2021/10/29
 * @describe
 */
@Data
@EqualsAndHashCode(callSuper = true)
@TableName(value = "sch_task_instance",autoResultMap = true)
public class TaskInstance extends SuperEntity {

    /**
     * task name
     */
    private String name;


    /**
     * task type
     */
    private TaskType taskType;

    /**
     * process instance id
     */
    private Long processInstanceId;

    /**
     * task code
     */
    private Long taskDefinitionId;
    /**
     * task 定义id
     */
    private Long taskDefinedId;

    /**
     * task definition version
     */
    private int taskDefinitionVersion;

    /**
     * process instance name
     */
    @TableField(exist = false)
    private String processInstanceName;

    /**
     * state
     */
    private ExecutionStatus state;

    /**
     * task first submit time.
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date firstSubmitTime;

    /**
     * task submit time
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date submitTime;

    /**
     * task start time
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date startTime;

    /**
     * task end time
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date endTime;

    /**
     * task host
     */
    private String host;

    /**
     * task shell execute path and the resource down from hdfs
     * default path: $base_run_dir/processInstanceId/taskInstanceId/retryTimes
     */
    private String executePath;

    /**
     * task log path
     * default path: $base_run_dir/processInstanceId/taskInstanceId/retryTimes
     */
    private String logPath;

    /**
     * retry times
     */
    private int retryTimes;

    /**
     * alert flag
     */
    private Flag alertFlag;

    /**
     * process instance
     */
    @TableField(exist = false)
    private ProcessInstance processInstance;

    /**
     * process definition
     */
    @TableField(exist = false)
    private ProcessDefinition processDefine;

    /**
     * task definition
     */
    @TableField(exist = false)
    private TaskDefinition taskDefine;

    /**
     * process id
     */
    private int pid;

    /**
     * appLink
     */
    private String appLink;

    /**
     * flag
     */
    private Flag flag;

    /**
     * duration
     */
    @TableField(exist = false)
    private String duration;

    /**
     * max retry times
     */
    private int maxRetryTimes;

    /**
     * task retry interval, unit: minute
     */
    private int retryInterval;

    private String taskContent;
    @TableField(exist = false)
    private AbstractParameters relationParameters;
    /**
     * task intance priority
     */
    private Priority taskInstancePriority;

    /**
     * process intance priority
     */
    @TableField(exist = false)
    private Priority processInstancePriority;

    /**
     * dependent state
     */
    @TableField(exist = false)
    private String dependentResult;


    /**
     * workerGroup
     */
    private Long workerGroupId;

    /**
     * environment code
     */
    private Long environmentId;

    /**
     * environment config
     */
    private String environmentConfig;

    private Long userId;
    private String username;
    private Long proId;
    private String proName;

    @TableField(jdbcType = JdbcType.VARCHAR, insertStrategy = NOT_NULL, typeHandler = ListPropToStringHandler.class)
    private List<Property> localParams;
    @TableField(jdbcType = JdbcType.VARCHAR, insertStrategy = NOT_NULL, typeHandler = ListPropToStringHandler.class)
    private List<Property> globalParams;

    /**
     * varPool string
     */
    @TableField(jdbcType = JdbcType.VARCHAR, insertStrategy = NOT_NULL, typeHandler = ListPropToStringHandler.class)
    private List<Property> varPool;
    @TableField(jdbcType = JdbcType.VARCHAR, insertStrategy = NOT_NULL, typeHandler = ListLongToStringHandler.class)
    private List<Long> resourceIds;
    @TableField(exist = false)
    private List<ResourceInfo> resources;

    /**
     * delay execution time.
     */
    private int delayTime;


    @TableField(jdbcType = JdbcType.VARCHAR, insertStrategy = NOT_NULL, typeHandler = TaskTimeoutParamsToStringHandler.class)
    private TaskTimeoutParameter timeoutParam;

    /**
     * dry run flag
     */
    private int dryRun;
    private Boolean isTmp;


    public boolean isSubProcess() {
        return TaskType.SUB_PROCESS.equals(this.taskType);
    }
    public boolean isTaskComplete() {

        return this.getState().typeIsPause()
                || this.getState().typeIsSuccess()
                || this.getState().typeIsCancel()
                || (this.getState().typeIsFailure() && !taskCanRetry());
    }
    /**
     * determine if you can try again
     *
     * @return can try result
     */
    public boolean taskCanRetry() {
        if (this.isSubProcess()) {
            return false;
        }
        if (this.getState() == ExecutionStatus.NEED_FAULT_TOLERANCE) {
            return true;
        } else {
            return (this.getState().typeIsFailure()
                    && this.getRetryTimes() < this.getMaxRetryTimes());
        }
    }
    public boolean isConditionsTask() {
        return TaskType.CONDITIONS.equals(this.taskType);
    }
    public boolean isFirstRun() {
        return endTime == null;
    }
    /**
     * whether the retry interval is timed out
     *
     * @return Boolean
     */
    public boolean retryTaskIntervalOverTime() {
        if (getState() != ExecutionStatus.FAILURE) {
            return true;
        }
        if (getId() == null
                || getMaxRetryTimes() == 0
                || getRetryInterval() == 0) {
            return true;
        }
        Date now = new Date();
        long failedTimeInterval = DateUtils.differSec(now, getEndTime());
        // task retry does not over time, return false
        return getRetryInterval() * SEC_2_MINUTES_TIME_UNIT < failedTimeInterval;
    }
    public boolean isDependTask() {
        return TaskType.DEPENDENT.equals(this.taskType);
    }



}
